/**
 * 
 */
package com.blumov.fastbox.infrastructure.persistence.largequery;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.transform.ResultTransformer;

/**
 * wrap aCriteria <br>
 * o aCriteria wrapper <br>
 * 
 * una implementacion de {@link LargeQuery} con {@link Criteria}
 * 
 * @author epidata
 * 
 */
@SuppressWarnings("unchecked")
public final class CriteriaForProjectionsWrapper<T> implements LargeQuery {

	private final Criteria aCriteria;
	private ProjectionList projections;
	private ResultTransformer transformer;
	private boolean hasRowCount;
	/**
	 * no debe accederse directamente
	 * 
	 * @see CriteriaForProjectionsWrapper#countRows()
	 */
	private Integer rowCount;

	/**
	 * wrap aCriteria
	 * 
	 * @param aCriteria el criterio de busqueda <br>
	 */
	public CriteriaForProjectionsWrapper(Criteria aCriteria, ProjectionList projections, ResultTransformer transformer) {
		this.aCriteria = aCriteria;
		this.projections = projections;
		this.transformer = transformer;
		this.hasRowCount = false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seecom.epidataconsulting.vonderheide.vdh.persistencia.queryobject.LargeQuery#list(com.
	 * epidataconsulting.vonderheide.vdh.persistencia.queryobject.Page)
	 */
	public List<T> list(Page thisPage) {
		thisPage.setTo(aCriteria);
		aCriteria.setProjection(projections);
		aCriteria.setResultTransformer(transformer);
		return (List<T>) aCriteria.list();
	}

	/*
	 * (non-Javadoc) Importante: esto es para reutilizar la aCriteria y poder listar los elementos
	 * aCriteria.setProjection(null); aCriteria.setResultTransformer(Criteria.ROOT_ENTITY); googlea:
	 * http://yettocome.blogspot.com/2005/10/hibernate-reusing-aCriteria-object-used.html
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.epidataconsulting.vonderheide.vdh.persistencia.queryobject.LargeQuery#countRows()
	 */
	public Integer countRows() {
		if (!hasRowCount) {
			Criteria criteriaRowCount = aCriteria.setProjection(Projections.rowCount());
			rowCount = (Integer) criteriaRowCount.uniqueResult();
			aCriteria.setProjection(null);
			aCriteria.setResultTransformer(Criteria.ROOT_ENTITY);
			hasRowCount = true;
		}
		return rowCount;
	}

}
